﻿//======================================================================
//
//	Cross-Platform XNA Menu System
//  http://cpxms.codeplex.com/
//
//  All code and content licensed under Microsoft Public License (Ms-PL)	
//
//======================================================================
//
//	File:		MenuProjectHost.cs
//
//	Author:		MJP
//
//	Date:		04/10/09
//
//======================================================================

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Xml.Serialization;

using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;

using CPXMenuEditor.Forms;

using CPXMenu;

namespace CPXMenuEditor
{
    public class MenuProjectHost
    {
        private bool previewMode = false;
        private Point drawOffset = new Point();
        private float zoom = 1.0f;
        private RenderTarget2D renderTarget;
        private SpriteBatch spriteBatch;
        private ActionManager actionManager;
        private MenuItem highlightedItem = null;
        private GraphicsDeviceService graphicsDeviceService;
        private GraphicsDevice graphicsDevice;
        private DepthStencilBuffer dsBuffer;
        private ServiceCollection serviceCollection;
        private MenuProject menuProject;
        private MainFrm mainForm;

        public bool PreviewMode
        {
            get { return previewMode; }
            set { previewMode = value; }
        }

        public float Zoom
        {
            get { return zoom; }
            set 
            { 
                zoom = MathHelper.Clamp(value, 0.05f, 10.0f); 
            }
        }

        public int DrawOffsetX
        {
            get { return drawOffset.X; }
            set { drawOffset.X = value; }
        }

        public int DrawOffsetY
        {
            get { return drawOffset.Y; }
            set { drawOffset.Y = value; }
        }

        public MenuItem HighlightedItem
        {
            get { return highlightedItem; }
            set { highlightedItem = value; }
        }

        public MenuProject MenuProject
        {
            get { return menuProject; }
            set 
			{ 
				menuProject = value;
				zoom = 1.0f;
			}
        }

        public ServiceCollection ServiceCollection
        {
            get { return serviceCollection; }
        }

        public GraphicsDeviceService GraphicsDeviceService
        {
            get { return graphicsDeviceService; }
        }

        public MenuProjectHost(MainFrm mainForm, ActionManager actionManager)
        {
            this.mainForm = mainForm;
            this.actionManager = actionManager;            

            graphicsDeviceService = new GraphicsDeviceService(mainForm.MenuEditorView.Handle);
            graphicsDeviceService.SetBackBufferDimensions(mainForm.MenuEditorView.Width, mainForm.MenuEditorView.Height);
            graphicsDevice = graphicsDeviceService.GraphicsDevice;
            serviceCollection = new ServiceCollection();
            serviceCollection.AddService<IGraphicsDeviceService>(graphicsDeviceService);            
            
            spriteBatch = new SpriteBatch(graphicsDevice);
         
        }

        public void CreateNewProject()
        {
            menuProject = new MenuProject();
            menuProject.Dimensions = new Point(1280, 720);
            menuProject.Initialize(serviceCollection, "Content");
            menuProject.ToggleDesignMode(true);

            Page page = (Page)menuProject.AddNewItemToProject(typeof(Page), menuProject);
        }		

        public MenuItem ClickTest(Point mousePos)
        {
            Rectangle boundingRect = GetBoundingRect();
            if (boundingRect.Contains(mousePos))                
                return menuProject.ClickTest(GetScaledMousePos(mousePos));            
            else
                return null;
        }

        public Point GetScaledMousePos(Point mousePos)
        {
            Rectangle boundingRect = GetBoundingRect();
            float scaledX = ((mousePos.X - boundingRect.X) / (float)boundingRect.Width) * menuProject.Dimensions.X;
            float scaledY = ((mousePos.Y - boundingRect.Y) / (float)boundingRect.Height) * menuProject.Dimensions.Y;
            return new Point((int)scaledX, (int)scaledY);
        }

        public void Update(float dt)
        {
            if (previewMode)
            {
                MenuInput input = MenuInput.GetMouseKBInput();
                input.CursorPos = GetScaledMousePos(input.CursorPos);
                menuProject.UpdateProject(input, dt);
            }
        }

        public void Render(float dt)
        {
			if (menuProject == null)
			{
				graphicsDevice.Clear(ClearOptions.Target, Color.Black, 1.0f, 0);
				return;
			}

            if (renderTarget == null)
                renderTarget = new RenderTarget2D(graphicsDevice, menuProject.Dimensions.X, menuProject.Dimensions.Y, 1, SurfaceFormat.Color);

            if (dsBuffer == null)
                dsBuffer = new DepthStencilBuffer(graphicsDevice, menuProject.Dimensions.X, menuProject.Dimensions.Y, graphicsDevice.DepthStencilBuffer.Format);

            if (menuProject.Dimensions.X != renderTarget.Width || menuProject.Dimensions.Y != renderTarget.Height)
            {
                renderTarget.Dispose();
                renderTarget = new RenderTarget2D(graphicsDevice, menuProject.Dimensions.X, menuProject.Dimensions.Y, 1, SurfaceFormat.Color);

                dsBuffer.Dispose();
                dsBuffer = new DepthStencilBuffer(graphicsDevice, menuProject.Dimensions.X, menuProject.Dimensions.Y, graphicsDevice.DepthStencilBuffer.Format);
            }

            DepthStencilBuffer originalDS = graphicsDevice.DepthStencilBuffer;
            graphicsDevice.DepthStencilBuffer = dsBuffer;
            graphicsDevice.SetRenderTarget(0, renderTarget);
            graphicsDevice.Clear(ClearOptions.Target, Color.Black, 1.0f, 0);

            menuProject.RenderProject(dt, actionManager.SelectedItems, highlightedItem);

            graphicsDevice.SetRenderTarget(0, null);
            graphicsDevice.DepthStencilBuffer = originalDS;
            graphicsDevice.Clear(Color.Black);

            Texture2D texture = renderTarget.GetTexture();

            spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);

            spriteBatch.Draw(texture, GetBoundingRect(), Color.White);
            spriteBatch.End();

            
        }

        public void EnterPreviewMode()
        {
            if (menuProject == null)
                return;

            if (previewMode)
                return;

            highlightedItem = null;

            menuProject.ToggleDesignMode(false);

            previewMode = true;
        }

        public void ExitPreviewMode()
        {
            if (menuProject == null)
                return;

            if (!previewMode)
                return;

            menuProject.ToggleDesignMode(true);

            previewMode = false;
        }


        private Rectangle GetBoundingRect()
        {
            if (renderTarget == null)
                return new Rectangle();

            float width = renderTarget.Width * zoom;
            float height = renderTarget.Height * zoom;
            int centerX = (int)((graphicsDeviceService.BackBufferWidth / 2.0f) - (width / 2.0f));
            int centerY = (int)((graphicsDeviceService.BackBufferHeight / 2.0f) - (height / 2.0f));
            return new Rectangle(centerX + drawOffset.X, centerY + drawOffset.Y, (int)width, (int)height);
        }

    }
}